Closed Bug 1934877 Opened 6 months ago Closed 1 month ago

Memory leak in tls13_MaybeGreaseEch

Categories

(NSS :: Libraries, defect)

defect

Tracking

(Not tracked)

RESOLVED FIXED

People

(Reporter: mdauer, Assigned: djackson)

References

(Blocks 1 open bug)

Details

Attachments

(2 files, 1 obsolete file)

OSS-Fuzz: https://oss-fuzz.com/testcase-detail/5766569436708864

Details

My uneducated guess would be that we reach this line twice, overwriting ss->ssl3.hs.greaseEchBuf, without having freed the previously allocated greaseBuf.

Reproduction

  1. Download the attached testcase
  2. Build NSS with ./build.sh -c --fuzz=tls
  3. Run /path/to/dist/Debug/bin/nssfuzz-tls-client /path/to/testcase

Stack trace

Direct leak of 1064 byte(s) in 1 object(s) allocated from:
	    #0 0x5a114c971d6c in __interceptor_realloc /src/llvm-project/compiler-rt/lib/asan/asan_malloc_linux.cpp:82:3
	    #1 0x5a114cadafd9 in PORT_Realloc_Util nss/lib/util/secport.c:101:14
	    #2 0x5a114cabee7c in sslBuffer_Grow nss/lib/ssl/sslencode.c:50:39
	    #3 0x5a114cabf6f2 in sslBuffer_AppendVariable nss/lib/ssl/sslencode.c:117:9
	    #4 0x5a114ca2ef18 in tls13_MaybeGreaseEch nss/lib/ssl/tls13ech.c:2258:10
	    #5 0x5a114ca6cb5a in ssl3_SendClientHello nss/lib/ssl/ssl3con.c:5620:18
	    #6 0x5a114ca9b833 in ssl3_HandleHelloRequest nss/lib/ssl/ssl3con.c:5787:10
	    #7 0x5a114ca84635 in ssl3_HandlePostHelloHandshakeMessage nss/lib/ssl/ssl3con.c:12747:18
	    #8 0x5a114ca84635 in ssl3_HandleHandshakeMessage nss/lib/ssl/ssl3con.c:12699:22
	    #9 0x5a114ca8c7d6 in ssl3_HandleHandshake nss/lib/ssl/ssl3con.c:12876:18
	    #10 0x5a114ca8c7d6 in ssl3_HandleNonApplicationData nss/lib/ssl/ssl3con.c:13411:22
	    #11 0x5a114ca8f561 in ssl3_HandleRecord nss/lib/ssl/ssl3con.c:13775:10
	    #12 0x5a114cab5e87 in ssl3_GatherCompleteHandshake nss/lib/ssl/ssl3gthr.c:560:18
	    #13 0x5a114cabce77 in ssl_GatherRecord1stHandshake nss/lib/ssl/sslcon.c:73:10
	    #14 0x5a114c9c66bb in ssl_Do1stHandshake nss/lib/ssl/sslsecur.c:43:14
	    #15 0x5a114c9c971e in SSL_ForceHandshake nss/lib/ssl/sslsecur.c:431:14
	    #16 0x5a114c9b5547 in TlsCommon::DoHandshake(PRFileDesc*, bool) nss/fuzz/targets/lib/tls/common.cc:57:10
	    #17 0x5a114c9b12ef in LLVMFuzzerTestOneInput nss/fuzz/targets/tls_client.cc:58:3
	    #18 0x5a114d11a7a0 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:614:13
	    #19 0x5a114d119fc5 in fuzzer::Fuzzer::RunOne(unsigned char const*, unsigned long, bool, fuzzer::InputInfo*, bool, bool*) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:516:7
	    #20 0x5a114d11bf52 in fuzzer::Fuzzer::ReadAndExecuteSeedCorpora(std::__Fuzzer::vector<fuzzer::SizedFile, std::__Fuzzer::allocator<fuzzer::SizedFile>>&) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:829:7
	    #21 0x5a114d11c242 in fuzzer::Fuzzer::Loop(std::__Fuzzer::vector<fuzzer::SizedFile, std::__Fuzzer::allocator<fuzzer::SizedFile>>&) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:867:3
	    #22 0x5a114d10b37b in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerDriver.cpp:914:6
	    #23 0x5a114d136752 in main /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerMain.cpp:20:10
	    #24 0x7c7459188082 in __libc_start_main /build/glibc-LcI20x/glibc-2.31/csu/libc-start.c:308:16
	
	================================================================================
	The following leaks are not necessarily related to the first leak.
	
	
	Direct leak of 1064 byte(s) in 1 object(s) allocated from:
	    #0 0x5a114c971d6c in __interceptor_realloc /src/llvm-project/compiler-rt/lib/asan/asan_malloc_linux.cpp:82:3
	    #1 0x5a114cadafd9 in PORT_Realloc_Util nss/lib/util/secport.c:101:14
	    #2 0x5a114cabee7c in sslBuffer_Grow nss/lib/ssl/sslencode.c:50:39
	    #3 0x5a114cabf6f2 in sslBuffer_AppendVariable nss/lib/ssl/sslencode.c:117:9
	    #4 0x5a114ca2ef18 in tls13_MaybeGreaseEch nss/lib/ssl/tls13ech.c:2258:10
	    #5 0x5a114ca6cb5a in ssl3_SendClientHello nss/lib/ssl/ssl3con.c:5620:18
	    #6 0x5a114cabd87a in ssl_BeginClientHandshake nss/lib/ssl/sslcon.c:189:10
	    #7 0x5a114c9c66bb in ssl_Do1stHandshake nss/lib/ssl/sslsecur.c:43:14
	    #8 0x5a114c9c971e in SSL_ForceHandshake nss/lib/ssl/sslsecur.c:431:14
	    #9 0x5a114c9b5547 in TlsCommon::DoHandshake(PRFileDesc*, bool) nss/fuzz/targets/lib/tls/common.cc:57:10
	    #10 0x5a114c9b12ef in LLVMFuzzerTestOneInput nss/fuzz/targets/tls_client.cc:58:3
	    #11 0x5a114d11a7a0 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:614:13
	    #12 0x5a114d119fc5 in fuzzer::Fuzzer::RunOne(unsigned char const*, unsigned long, bool, fuzzer::InputInfo*, bool, bool*) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:516:7
	    #13 0x5a114d11bf52 in fuzzer::Fuzzer::ReadAndExecuteSeedCorpora(std::__Fuzzer::vector<fuzzer::SizedFile, std::__Fuzzer::allocator<fuzzer::SizedFile>>&) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:829:7
	    #14 0x5a114d11c242 in fuzzer::Fuzzer::Loop(std::__Fuzzer::vector<fuzzer::SizedFile, std::__Fuzzer::allocator<fuzzer::SizedFile>>&) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:867:3
	    #15 0x5a114d10b37b in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerDriver.cpp:914:6
	    #16 0x5a114d136752 in main /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerMain.cpp:20:10
	    #17 0x7c7459188082 in __libc_start_main /build/glibc-LcI20x/glibc-2.31/csu/libc-start.c:308:16
	
	SUMMARY: AddressSanitizer: 2128 byte(s) leaked in 2 allocation(s).

The severity field is not set for this bug.
:beurdouche, could you have a look please?

For more information, please visit BugBot documentation.

Flags: needinfo?(bbeurdouche)
Group: crypto-core-security
Flags: needinfo?(bbeurdouche) → needinfo?(djackson)

What is the concern about having a memory leak bug be public?

Keywords: sec-other

(In reply to Maurice Dauer [:mdauer] from comment #0)

Created attachment 9441321 [details]
clusterfuzz-testcase-tls-client-5766569436708864

OSS-Fuzz: https://oss-fuzz.com/testcase-detail/5766569436708864

Details

My uneducated guess would be that we reach this line twice, overwriting ss->ssl3.hs.greaseEchBuf, without having freed the previously allocated greaseBuf.

Reproduction

  1. Download the attached testcase
  2. Build NSS with ./build.sh -c --fuzz=tls
  3. Run /path/to/dist/Debug/bin/nssfuzz-tls-client /path/to/testcase

Stack trace

Direct leak of 1064 byte(s) in 1 object(s) allocated from:
	    #0 0x5a114c971d6c in __interceptor_realloc /src/llvm-project/compiler-rt/lib/asan/asan_malloc_linux.cpp:82:3
	    #1 0x5a114cadafd9 in PORT_Realloc_Util nss/lib/util/secport.c:101:14
	    #2 0x5a114cabee7c in sslBuffer_Grow nss/lib/ssl/sslencode.c:50:39
	    #3 0x5a114cabf6f2 in sslBuffer_AppendVariable nss/lib/ssl/sslencode.c:117:9
	    #4 0x5a114ca2ef18 in tls13_MaybeGreaseEch nss/lib/ssl/tls13ech.c:2258:10
	    #5 0x5a114ca6cb5a in ssl3_SendClientHello nss/lib/ssl/ssl3con.c:5620:18
	    #6 0x5a114ca9b833 in ssl3_HandleHelloRequest nss/lib/ssl/ssl3con.c:5787:10
	    #7 0x5a114ca84635 in ssl3_HandlePostHelloHandshakeMessage nss/lib/ssl/ssl3con.c:12747:18
	    #8 0x5a114ca84635 in ssl3_HandleHandshakeMessage nss/lib/ssl/ssl3con.c:12699:22
	    #9 0x5a114ca8c7d6 in ssl3_HandleHandshake nss/lib/ssl/ssl3con.c:12876:18
	    #10 0x5a114ca8c7d6 in ssl3_HandleNonApplicationData nss/lib/ssl/ssl3con.c:13411:22
	    #11 0x5a114ca8f561 in ssl3_HandleRecord nss/lib/ssl/ssl3con.c:13775:10
	    #12 0x5a114cab5e87 in ssl3_GatherCompleteHandshake nss/lib/ssl/ssl3gthr.c:560:18
	    #13 0x5a114cabce77 in ssl_GatherRecord1stHandshake nss/lib/ssl/sslcon.c:73:10
	    #14 0x5a114c9c66bb in ssl_Do1stHandshake nss/lib/ssl/sslsecur.c:43:14
	    #15 0x5a114c9c971e in SSL_ForceHandshake nss/lib/ssl/sslsecur.c:431:14
	    #16 0x5a114c9b5547 in TlsCommon::DoHandshake(PRFileDesc*, bool) nss/fuzz/targets/lib/tls/common.cc:57:10
	    #17 0x5a114c9b12ef in LLVMFuzzerTestOneInput nss/fuzz/targets/tls_client.cc:58:3
	    #18 0x5a114d11a7a0 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:614:13
	    #19 0x5a114d119fc5 in fuzzer::Fuzzer::RunOne(unsigned char const*, unsigned long, bool, fuzzer::InputInfo*, bool, bool*) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:516:7
	    #20 0x5a114d11bf52 in fuzzer::Fuzzer::ReadAndExecuteSeedCorpora(std::__Fuzzer::vector<fuzzer::SizedFile, std::__Fuzzer::allocator<fuzzer::SizedFile>>&) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:829:7
	    #21 0x5a114d11c242 in fuzzer::Fuzzer::Loop(std::__Fuzzer::vector<fuzzer::SizedFile, std::__Fuzzer::allocator<fuzzer::SizedFile>>&) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:867:3
	    #22 0x5a114d10b37b in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerDriver.cpp:914:6
	    #23 0x5a114d136752 in main /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerMain.cpp:20:10
	    #24 0x7c7459188082 in __libc_start_main /build/glibc-LcI20x/glibc-2.31/csu/libc-start.c:308:16
	
	================================================================================
	The following leaks are not necessarily related to the first leak.
	
	
	Direct leak of 1064 byte(s) in 1 object(s) allocated from:
	    #0 0x5a114c971d6c in __interceptor_realloc /src/llvm-project/compiler-rt/lib/asan/asan_malloc_linux.cpp:82:3
	    #1 0x5a114cadafd9 in PORT_Realloc_Util nss/lib/util/secport.c:101:14
	    #2 0x5a114cabee7c in sslBuffer_Grow nss/lib/ssl/sslencode.c:50:39
	    #3 0x5a114cabf6f2 in sslBuffer_AppendVariable nss/lib/ssl/sslencode.c:117:9
	    #4 0x5a114ca2ef18 in tls13_MaybeGreaseEch nss/lib/ssl/tls13ech.c:2258:10
	    #5 0x5a114ca6cb5a in ssl3_SendClientHello nss/lib/ssl/ssl3con.c:5620:18
	    #6 0x5a114cabd87a in ssl_BeginClientHandshake nss/lib/ssl/sslcon.c:189:10
	    #7 0x5a114c9c66bb in ssl_Do1stHandshake nss/lib/ssl/sslsecur.c:43:14
	    #8 0x5a114c9c971e in SSL_ForceHandshake nss/lib/ssl/sslsecur.c:431:14
	    #9 0x5a114c9b5547 in TlsCommon::DoHandshake(PRFileDesc*, bool) nss/fuzz/targets/lib/tls/common.cc:57:10
	    #10 0x5a114c9b12ef in LLVMFuzzerTestOneInput nss/fuzz/targets/tls_client.cc:58:3
	    #11 0x5a114d11a7a0 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:614:13
	    #12 0x5a114d119fc5 in fuzzer::Fuzzer::RunOne(unsigned char const*, unsigned long, bool, fuzzer::InputInfo*, bool, bool*) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:516:7
	    #13 0x5a114d11bf52 in fuzzer::Fuzzer::ReadAndExecuteSeedCorpora(std::__Fuzzer::vector<fuzzer::SizedFile, std::__Fuzzer::allocator<fuzzer::SizedFile>>&) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:829:7
	    #14 0x5a114d11c242 in fuzzer::Fuzzer::Loop(std::__Fuzzer::vector<fuzzer::SizedFile, std::__Fuzzer::allocator<fuzzer::SizedFile>>&) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:867:3
	    #15 0x5a114d10b37b in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerDriver.cpp:914:6
	    #16 0x5a114d136752 in main /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerMain.cpp:20:10
	    #17 0x7c7459188082 in __libc_start_main /build/glibc-LcI20x/glibc-2.31/csu/libc-start.c:308:16
	
	SUMMARY: AddressSanitizer: 2128 byte(s) leaked in 2 allocation(s).

I think you're right. I think what happens here is the following:

  1. We send a clientHello and call tls13_MaybeGreaseEch
  2. We send the second clientHello, but now with client_hello_renegotiation CH type
  3. Pretty much we arrive to the same function, and again ss->ssl3.hs.greaseEchBuf = greaseBuf;

The thing is that IIUC, client_hello_renegotiation is for <TLS1.3, whereas ECH/Grease are TLS1.3
I would suggest to extend tls13_MaybeGreaseEch with CH type and return SECSuccess if we see client_hello_renegotiation.
And to put PORT_Assert(ss->ssl3.hs.greaseEchBuf.len == 0);

Important, I don't know ECH enough and my suggestion could be incorrect!

Assignee: nobody → mdauer
Status: NEW → ASSIGNED
Attachment #9471094 - Attachment description: Bug 1934877 - Correct TLS version check for ECH/Grease, r?#nss-reviewers → WIP: Bug 1934877 - Fix memory leak in tls13_MaybeGreaseEch
Attachment #9471094 - Attachment is obsolete: true
Assignee: mdauer → nobody
Status: ASSIGNED → NEW
Assignee: nobody → djackson
Flags: needinfo?(djackson)

You were both spot on with the diagnosis, the test harness just needed a small tweak to force the server to use 1.2 and trigger renegotiation correctly.

This is a really nice find insofar as it is absolutely a scenario we (I) could of and should of written a test for, but it slipped through.

Status: NEW → RESOLVED
Closed: 1 month ago
Resolution: --- → FIXED
Group: crypto-core-security
Keywords: sec-other
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: